package com.ease.lang {
   import flash.utils.getQualifiedClassName;

   public class Enum {
	   
      public function get name():String {
         return _name;
      }

      public function set name(value:String):void {
         this._name = value;
      }

      public function get index():int {
         return _index;
      }

      public function toString():String {
         return name;
      }

      public static function getEnumConstants(type:Class):Array {
         var constants:EnumConstants = _enumDb[getQualifiedClassName(type)];
         if (constants == null)
            return null;
         return constants.byIndex.slice();
      }

      public static function get(i_type:Class, i_constantName:String, i_caseSensitive:Boolean = false):Enum {
         var constants:EnumConstants = _enumDb[getQualifiedClassName(i_type)];
         if (constants == null)
            return null;

         var constant:Enum = constants.byName[i_constantName.toLowerCase()];
         if (i_caseSensitive && (constant != null) && (i_constantName != constant.name))
            return null;

         return constant;
      }

      function Enum() {
         var typeName:String = getQualifiedClassName(this);
         if (_enumDb[typeName] != null) {
            return;
         }

         var constants:Array = _pendingDb[typeName];
         if (constants == null)
            _pendingDb[typeName] = constants = [];

         _index = constants.length;
         constants.push(this);
      }

      protected static function initEnum(i_type:Class):void {
         var typeName:String = getQualifiedClassName(i_type);

         if (_enumDb[typeName] != null) {
            return;
         }
         var constants:Array = _pendingDb[typeName];
         if (constants == null) {
           return;
         }

         // process constants
         var type:XML = flash.utils.describeType(i_type);
         for each (var constant:XML in type.constant) {
            // this will fail to coerce if the type isn't inherited from Enum
            var enumConstant:Enum = i_type[constant.@name];

            var enumConstantType:* = Object(enumConstant).constructor;
            if (enumConstantType != i_type) {
               throw new Error("Constant type '" + enumConstantType + "' " + "does not match its enum class '" + i_type + "'");
            }

            enumConstant._name = constant.@name;
         }

         // now seal it
         _pendingDb[typeName] = null;
         _enumDb[typeName] = new EnumConstants(constants);
      }

      private var _name:String = null;
      private var _index:int = -1;

      private static var _pendingDb:Object = {}; // typename -> [constants]
      private static var _enumDb:Object = {}; // typename -> EnumConstants
   }
}